-- @preview-file on clear
-- @preview-file on clear
-- @preview-file on clear
-- @preview-file on clear
local Sprite <const> = require("Sprite")
local Node <const> = require("Node")
local Keyboard = require("Keyboard")
local App = require("App")
local Vec2 <const> = require("Vec2")
local Director <const> = require("Director")
local PhysicsWorld <const> = require("PhysicsWorld")
local Body <const> = require("Body")
local BodyDef <const> = require("BodyDef")
local Mouse = require("Mouse")
local Audio <const> = require("Audio")
local math <const> = require("math")
local ImGui <const> = require("ImGui")
local threadLoop <const> = require("threadLoop")
local Color <const> = require("Color")
local Color3 <const> = require("Color3")
local Label <const> = require("Label")
local Rect <const> = require("Rect")
local View <const> = require("View") -- [新增] 用于获取视图尺寸
local Size <const> = require("Size") -- [新增] 用于尺寸对象
local Line <const> = require("Line") -- [新增] 用于绘制线段
-- 游戏状态管理
local GameState = {
    MENU = 1,
    PROLOGUE = 2, -- 海底序章
    HOSPITAL = 3, -- 医院序章
    BRIDGE = 4, -- 星空桥梁序章
    SKYGRASS = 5, -- 新增天空草地序章
    GAMEPLAY = 6 -- 正式游戏
}
local currentState = GameState.MENU
local root = Node()
-- 变量管理
local pauseLayer = nil
local isImGuiMenuOpen = false
-- 启用键盘事件回调
root.keyboardEnabled = true
-- [新增] 屏幕自适应逻辑 ==========================================
local DesignSceneHeight <const> = 1080 -- 定义设计分辨率高度
-- 更新摄像机缩放，确保场景高度适配设计高度
local function updateViewSize()
local zoom = View.size.height / DesignSceneHeight
    Director.currentCamera.zoom = zoom
end
-- 监听应用窗口变化事件
Director.entry:onAppChange(function(settingName)
if settingName == "Size" then
        updateViewSize()
end
end)
-- 初始化调用一次
updateViewSize()
-- [新增] 创建自适应全屏背景的辅助函数
-- 逻辑：类似 CSS 的 object-fit: cover，保证图片铺满屏幕
local function createAdaptBackground(parent, filename, fallbackColor)
local bg = Sprite(filename)
if not bg then
        bg = Sprite()
        bg.color = fallbackColor or Color(0, 0, 0, 255)
end
    parent:addChild(bg)
-- 更新背景尺寸和缩放的函数
local function updateBgLayout()
local zoom = View.size.height / DesignSceneHeight
-- 计算当前视野在游戏坐标系中的实际宽高
-- 高度固定为 DesignSceneHeight (1080)
-- 宽度随屏幕比例变化
local visibleWidth = View.size.width / zoom
local visibleHeight = DesignSceneHeight
if bg.texture then
local texW = bg.texture.width
local texH = bg.texture.height
-- 计算宽和高的缩放比，取最大值以保证铺满
local scaleX = visibleWidth / texW
local scaleY = visibleHeight / texH
local scale = math.max(scaleX, scaleY)
            bg.scaleX = scale
            bg.scaleY = scale
else
-- 如果没有图片，直接设置尺寸
            bg.size = Size(visibleWidth, visibleHeight)
end
-- 确保背景在屏幕中心
        bg.position = Vec2.zero
end
-- 立即执行一次布局
    updateBgLayout()
-- 监听窗口变化，实时调整背景
    bg:gslot("AppChange", function(settingName)
if settingName == "Size" then
            updateBgLayout()
end
end)
return bg
end
-- ==============================================================
-- 前置声明
local createGameScene
local createMenuScene
local createPrologueScene
local createHospitalScene
local createBridgeScene
local createSkyGrassScene
-- ====== 天空草地场景 (SkyGrass Scene) ======
createSkyGrassScene = function()
    root:removeAllChildren()
--tipLabel.position = Vec2(300, -50);
        Audio:stopStream()
        Audio:playStream("music/countryyard.MP3")
local back=Sprite("image/sky.jpg")
        root:addChild(back)
local tipLabel = Label("Sarasa-Mono-SC-Regular", 24)
    tipLabel.text = "";
        tipLabel.color = Color(255, 255, 255, 255);
        tipLabel.position = Vec2(300, -50)
        tipLabel.zOrder = 100
local anxia=Sprite("image/anxia.png")
local huidao = Sprite("image/huidao.png")
--root:addChild(anxia)
    currentState = GameState.SKYGRASS
-- 1. 使用自适应背景
    createAdaptBackground(root, nil, Color(135, 206, 235, 255))
-- 2. 物理世界
local world = PhysicsWorld()
--local back=Sprite("image/sky.jpg")
--root:addChild(back)
    world.gravity = Vec2(0, -3000)
    world.showDebug = false -- 关闭调试框以便看清图片
    root:addChild(world)
    world:setShouldContact(0, 0, true)
-- 3. 草地地面 (平坦)
local groundDef = BodyDef()
    groundDef.type = "Static"
    groundDef:attachPolygon(12000, 50, 1, 0.8, 0.0)
local groundBody = Body(groundDef, world, Vec2(0, -500))
    world:addChild(groundBody)
local groundSprite = Sprite("image/ground.png")
local groundSprite2 = Sprite("image/ground.png")
local groundSprite3 = Sprite("image/ground.png")
if groundSprite then
        groundSprite.scaleX = 2.0
        groundSprite.scaleY = 2.0
        groundSprite.position = Vec2(0, 0)
        groundBody:addChild(groundSprite)
                groundBody:addChild(groundSprite2)
								groundBody:addChild(groundSprite3)
                groundSprite2.x=3070
                groundSprite2.scaleY=2.0
								groundSprite3.x=5000
                groundSprite3.scaleY=2.0
else
local debugGround = Sprite()
        debugGround.size = Vec2(1400, 50)
        debugGround.color = Color(0, 128, 0, 255)
        groundBody:addChild(debugGround)
end
local gravity=Vec2(0,-200)
-- 4. 主角
local playerDef = BodyDef()
    playerDef.type = "Dynamic"
    playerDef.linearDamping = 0.0
    playerDef.fixedRotation = true
    playerDef:attachPolygon(50, 50, 1, 0.0, 0.0)
local playerBody = Body(playerDef, world, Vec2(-600, -300))
    world:addChild(playerBody)
local playerSprite = Sprite("image/walk.png")
local frameWidth = 0
local frameHeight = 0
if playerSprite and playerSprite.texture then
        frameWidth = playerSprite.texture.width / 4
        frameHeight = playerSprite.texture.height
        playerSprite.textureRect = Rect(frameWidth, 0, frameWidth, frameHeight)
else
        playerSprite = Sprite("default.png")
end
    playerSprite.scaleX = 0.6
    playerSprite.scaleY = 2.0
    playerBody:addChild(playerSprite)
        playerSprite.y=100
-- ==========================================
-- 4.5 [新增] 石墙 (Stone Wall)
-- ==========================================
-- 我们将墙放在按钮的同一 X 轴位置 (300)
-- 地面中心 Y 是 -500，上面边缘是 -475
-- 按钮在 -450。我们让墙体高一点，作为背景支撑
local wallDef = BodyDef()
    wallDef.type = "Static"
        wallDef.linearAcceleration = gravity
-- 定义一个宽 100，高 200 的墙体
    wallDef:attachPolygon(0,0, 1, 0.5, 0.0)
local brickDef=BodyDef()
        brickDef.type="Dynamic"
        brickDef.linearAcceleration = gravity
        brickDef:attachPolygon(200,200, 1, 0.5, 0.0)
local brickDef2=BodyDef()
        brickDef2.type="Dynamic"
        brickDef2.linearAcceleration = gravity
        brickDef2:attachPolygon(200,400, 1, 0.5, 0.0)
local brickDef3=BodyDef()
        brickDef3.type="Static"
        brickDef3.linearAcceleration = gravity
        brickDef3:attachPolygon(200,600, 1, 0.5, 0.0)
-- 放置在 (300, -400)。
-- 这样墙的底部在 -500 (插入地面)，顶部在 -300。
-- 按钮在 -450，正好位于墙的中下部。
local wallBody = Body(wallDef, world, Vec2(300, -400))
local wallBody2 = Body(wallDef, world, Vec2(1400, -400))
local brickBody = Body(brickDef, world, Vec2(2300, -400))
local brickBody2 = Body(brickDef2, world, Vec2(2600, 400))
local brickBody3 = Body(brickDef3, world, Vec2(2900, -200))
local wallSprite3 = Sprite("image/stone wall.png")
        wallSprite3.scaleX=1.7
        wallSprite3.scaleY=1.7
--local wallBody2 = Body(wallDef, world, Vec2(1300, -400))
    world:addChild(wallBody)
        world:addChild(wallBody2)
        brickBody:addChild(wallSprite3)
        wallBody.y=-100
local wallSprite = Sprite("image/stone wall.png")
local wallSprite2 = Sprite("image/stone wall.png")
local wallSprite4 = Sprite("image/stone wall.png")
local wallSprite5 = Sprite("image/stone wall.png")
        brickBody2:addChild(wallSprite4)
        wallSprite4.scaleX=1.7
        wallSprite4.scaleY=3.4
        brickBody3:addChild(wallSprite5)
        wallSprite5.scaleX=1.7
        wallSprite5.scaleY=5.1
        wallSprite.y=-220
if not wallSprite then
-- 兜底显示灰色石墙
        wallSprite = Sprite()
        wallSprite.size = Vec2(100, 200)
        wallSprite.color = Color(105, 105, 105, 255)
else
-- 简单的缩放适配逻辑，假设图片可能大小不一
local w = wallSprite.texture.width
local h = wallSprite.texture.height
        wallSprite.scaleX = 3.0
        wallSprite.scaleY = 3.0
end
    wallBody:addChild(wallSprite)
        wallBody2:addChild(wallSprite2)
        wallSprite2.scaleX = 3.0
    wallSprite2.scaleY = 3.0
        wallSprite2.y = 100
        wallSprite:addChild(anxia)
        anxia.scaleX=0.5
        anxia.scaleY=0.25
        anxia.y=100
        anxia.x=100
        anxia.visible=false
-- ==========================================
-- 5. 木按钮 (Wooden Button)
-- ==========================================
local buttonDef = BodyDef()
    buttonDef.type = "Static"
local BUTTON_TAG = 1
    buttonDef:attachDiskSensor(BUTTON_TAG, Vec2(0, 0), 50)
-- 按钮位置不变，位于墙体表面
local buttonBody = Body(buttonDef, world, Vec2(300, -350))
local buttonBody2 = Body(buttonDef, world, Vec2(1400, -350))
    world:addChild(buttonBody)
    world:addChild(buttonBody2)
local buttonSprite = Sprite("image/wooden button.png")
local buttonSprite2 = Sprite("image/wooden button.png")
local buttonW, buttonH = 0, 0
if buttonSprite and buttonSprite.texture then
        buttonW = buttonSprite.texture.width / 2
        buttonH = buttonSprite.texture.height
        buttonSprite.textureRect = Rect(0, 0, buttonW, buttonH)
else
        buttonSprite = Sprite()
        buttonSprite.size = Vec2(100, 100)
        buttonSprite.color = Color(139, 69, 19, 255)
end
if buttonSprite2 and buttonSprite2.texture then
        buttonW = buttonSprite2.texture.width / 2
        buttonH = buttonSprite2.texture.height
        buttonSprite2.textureRect = Rect(0, 0, buttonW, buttonH)
else
        buttonSprite2 = Sprite()
        buttonSprite2.size = Vec2(100, 100)
        buttonSprite2.color = Color(139, 69, 19, 255)
end
-- 确保按钮显示在墙的前面 (虽然添加顺序已经保证了，但也可以设ZOrder)
    buttonSprite.zOrder = 1
        buttonSprite2.zOrder = 1
    buttonSprite.scaleX = 2.0
    buttonSprite.scaleY = 2.0
        buttonSprite2.scaleX = 2.0
    buttonSprite2.scaleY = 2.0
    buttonBody:addChild(buttonSprite)
        buttonBody2:addChild(buttonSprite2)
    buttonSprite.touchEnabled = true
-- ==========================================
-- 6. 木门 (Wooden Door)
-- ==========================================
local doorDef = BodyDef()
    doorDef.type = "Static"
local DOOR_TAG = 2
-- 1. 保留传感器 (关键！)：用于检测挥刀连接和玩家进门逻辑
    doorDef:attachDiskSensor(DOOR_TAG, Vec2(0, 0), 60)
-- 2. [新增] 物理碰撞盒：让门像墙一样有实体，不可穿过
-- 假设门宽80，高120 (与下方兜底尺寸一致)
    doorDef:attachPolygon(80, 1200, 1, 0.0, 0.0)
local doorBody = Body(doorDef, world, Vec2(600, -350))
local doorBody2 = Body(doorDef, world, Vec2(2600, 50))
        doorBody2.angle=90
    world:addChild(doorBody)
        world:addChild(doorBody2)
local doorSprite = Sprite("image/wooden door.png")
local doorSprite2 = Sprite("image/wooden door.png")
local doorW, doorH = 0, 0
if doorSprite and doorSprite.texture then
        doorW = doorSprite.texture.width / 2
        doorH = doorSprite.texture.height
        doorSprite.textureRect = Rect(0, 0, doorW, doorH)
else
        doorSprite = Sprite()
        doorSprite.size = Vec2(80, 120)
        doorSprite.color = Color(139, 69, 19, 255)
end
    doorSprite.scaleX = 2.4
    doorSprite.scaleY = 4.0
if doorSprite2 and doorSprite2.texture then
        doorW = doorSprite.texture.width / 2
        doorH = doorSprite.texture.height
        doorSprite2.textureRect = Rect(0, 0, doorW, doorH)
else
        doorSprite2 = Sprite()
        doorSprite2.size = Vec2(80, 120)
        doorSprite2.color = Color(139, 69, 19, 255)
end
    doorSprite.scaleX = 2.4
    doorSprite.scaleY = 4.0
        doorSprite2.scaleX = 2.4
    doorSprite2.scaleY = 4.0
    doorBody:addChild(doorSprite)
        doorBody2:addChild(doorSprite2)
        doorSprite2.x=100
        doorSprite.y=50
        doorSprite.x=100
        doorSprite:addChild(huidao)
        huidao.y=100
        huidao.visible=false
-- ==========================================
-- 7. 逻辑控制
-- ==========================================
local canMove = true
local contactCount = 0
playerBody:onContactStart(function(other)
-- 只要不是刀（knifeBody），也不是玩家自己，就认为是可以站立的平台
if other ~= knifeBody then
        contactCount = contactCount + 1
end
end)
playerBody:onContactEnd(function(other)
if other ~= knifeBody then
        contactCount = contactCount - 1
end
end)
-- ==========================================
-- 8. 挥刀逻辑 (Press E)
-- ==========================================
local lastEPressed = false
local knifeFrames = {
"image/knife/knife0000.png", "image/knife/knife0002.png", "image/knife/knife0004.png",
"image/knife/knife0006.png", "image/knife/knife0008.png", "image/knife/knife0010.png",
"image/knife/knife0011.png", "image/knife/knife0013.png"
    }
local currentKnifeFrame = 0
local knifeAnimTimer = 0
local frameDuration = 0.03
local knifeNode = Node()
    knifeNode.zOrder = 10
    playerBody:addChild(knifeNode)
        knifeNode.scaleX=3.0
        knifeNode.scaleY=3.0
        knifeNode.y=100
local knifeBody = nil
local KNIFE_GROUP = 3
    world:setShouldContact(0, KNIFE_GROUP, true)
-- ==========================================
-- 9. 连接逻辑 (Lights and Line)
-- ==========================================
local buttonLight = nil
local swordNode = nil
local swordLight = nil
local doorLight = nil
local connectionLine = nil
local isButtonTriggered = false
local isDoorTriggered = false
local isButtonPressed = false
local isDoorOpen = false
local function createConnectionLine(startPos, endPos)
if connectionLine then connectionLine:removeFromParent() end
        connectionLine = Line({startPos, endPos}, Color(255, 255, 0, 255))
        connectionLine.zOrder = 5
        root:addChild(connectionLine)
end
    root:schedule(function()
if connectionLine then
local startPos = buttonBody:convertToWorldSpace(Vec2.zero)
local endPos
if isDoorTriggered then
                endPos = doorSprite
elseif swordNode then
                endPos = playerBody:convertToWorldSpace(swordNode.position + Vec2(0, swordNode.height / 2))
end
if endPos then
                connectionLine:set({startPos, endPos})
end
end
end)
-- ==========================================
-- 10. 碰撞事件处理
-- ==========================================
    buttonBody:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == BUTTON_TAG and not isButtonTriggered then
            isButtonTriggered = true
            buttonLight = Sprite("image/light.png")
if buttonLight then
                buttonLight.scaleX = 0.5; buttonLight.scaleY = 0.5
                buttonBody:addChild(buttonLight)
end
            swordNode = Sprite("image/sword.png")
if swordNode then
                swordNode.x = (playerSprite.scaleX > 0) and 30 or -30
                swordNode.y = 20
                swordNode.scaleX = (playerSprite.scaleX > 0) and 1.0 or -1.0
                swordNode.scaleY = 1.0
                knifeNode:addChild(swordNode)
end
            swordLight = Sprite("image/light.png")
if swordLight then
                swordLight.scaleX = 0.5; swordLight.scaleY = 0.5
                swordLight.y = swordNode.height / 2
                swordNode:addChild(swordLight)
end
local startPos = buttonBody:convertToWorldSpace(Vec2.zero)
local endPos = playerBody:convertToWorldSpace(swordNode.position + Vec2(0, swordNode.height / 2))
            createConnectionLine(startPos, endPos)
end
end)
    doorBody:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == DOOR_TAG and isButtonTriggered and not isDoorTriggered then
            isDoorTriggered = true
            doorLight = Sprite("image/light.png")
if doorLight then
                doorLight.scaleX = 0.5; doorLight.scaleY = 0.5
                doorBody:addChild(doorLight)
end
if swordNode then swordNode:removeFromParent(); swordNode = nil end
if swordLight then swordLight:removeFromParent(); swordLight = nil end
local startPos = buttonBody:convertToWorldSpace(Vec2.zero)
local endPos = doorBody:convertToWorldSpace(Vec2.zero)
            createConnectionLine(startPos, endPos)
end
end)
-- ==========================================
-- 11. 按钮点击逻辑
-- ==========================================
buttonSprite:onTapped(function()
if isDoorTriggered then
            isButtonPressed = not isButtonPressed
if isButtonPressed then
                buttonSprite.textureRect = Rect(buttonW, 0, buttonW, buttonH)
                isDoorOpen = true
                doorSprite.textureRect = Rect(doorW, 0, doorW, doorH)
-- 移除门的物理碰撞盒，让主角可以通过
                doorBody.y=doorBody.y+10000
                                doorSprite.y=doorSprite.y-10000
-- 保留传感器以检测进入
                doorDef = BodyDef()
                doorDef.type = "Static"
                doorDef:attachDiskSensor(DOOR_TAG, Vec2(0, 0), 60)
                doorBody.definition = doorDef
else
                buttonSprite.textureRect = Rect(0, 0, buttonW, buttonH)
                isDoorOpen = false
                doorSprite.textureRect = Rect(0, 0, doorW, doorH)
-- 恢复门的物理碰撞盒
                doorBody.y=doorBody.y-10000
                                doorSprite.y=doorSprite.y+10000
end
end
end)
-- ==========================================
-- 12. 玩家移动与挥刀
-- ==========================================
local lastSpacePressed = false
local animTimer = 0
local animInterval = 0.12
local frameIndex = 1
    playerBody:schedule(function(deltaTime)
local adistance = math.abs(playerBody.x - buttonBody.x)
if adistance < 100 and not isButtonTriggered then -- 150 是触发距离，可自行调整
                anxia.visible=true
else
                anxia.visible=false
end
local bdistance = math.abs(playerBody.x - doorBody.x)
if bdistance < 150 and not isButtonTriggered then -- 150 是触发距离，可自行调整
                huidao.visible=true
else
                huidao.visible=false
end
if not canMove then return end
local currentVel = playerBody.velocity
local moveSpeed = 300
local jumpForce = 1200
local targetVx = 0
local targetVy = currentVel.y
local isMoving = false
if Keyboard:isKeyPressed("A") then
            targetVx = -moveSpeed
if playerSprite.scaleX > 0 then playerSprite.scaleX = -math.abs(playerSprite.scaleX) end
            isMoving = true
elseif Keyboard:isKeyPressed("D") then
            targetVx = moveSpeed
if playerSprite.scaleX < 0 then playerSprite.scaleX = math.abs(playerSprite.scaleX) end
            isMoving = true
end
                Director.currentCamera.position=playerBody.position
                back.position=playerBody.position
if isMoving and playerSprite.texture then
            animTimer = animTimer + deltaTime
if animTimer >= animInterval then
                animTimer = 0
                frameIndex = (frameIndex + 1) % 4
                playerSprite.textureRect = Rect(frameIndex * frameWidth, 0, frameWidth, frameHeight)
end
elseif playerSprite.texture then
if frameIndex ~= 1 then
                frameIndex = 1
                playerSprite.textureRect = Rect(frameIndex * frameWidth, 0, frameWidth, frameHeight)
end
end
local isSpaceDown = Keyboard:isKeyPressed("Space")
local isSpaceJustPressed = isSpaceDown and not lastSpacePressed
local isGrounded = (contactCount > 0) and (math.abs(currentVel.y) < 5.0)
if isSpaceJustPressed and isGrounded then
            targetVy = jumpForce
end
        targetVy = targetVy + (world.gravity.y * deltaTime)
if targetVy > 0 and not isSpaceDown then targetVy = targetVy + (world.gravity.y * 2.0 * deltaTime) end
if targetVy < 0 then targetVy = targetVy + (world.gravity.y * 0.5 * deltaTime) end
if Keyboard:isKeyPressed("S") and not isGrounded then targetVy = -1500 end
        playerBody.velocity = Vec2(targetVx, targetVy)
if playerBody.y < -800 then
            playerBody.position = Vec2(-600, -400)
            playerBody.velocity = Vec2(0, 0)
end
        lastSpacePressed = isSpaceDown
-- 挥刀 (E key)
local isEDown = Keyboard:isKeyPressed("E")
if isEDown and not lastEPressed then
            currentKnifeFrame = 1; knifeAnimTimer = 0; knifeNode:removeAllChildren()
local s = Sprite(knifeFrames[1])
if s then
                s.x = (playerSprite.scaleX > 0) and 60 or -30
                s.scaleX = (playerSprite.scaleX > 0) and 1.0 or -1.0
                s.y = 10
                knifeNode:addChild(s)
end
local knifeDef = BodyDef()
            knifeDef.type = "Dynamic"
            knifeDef:attachPolygon(300, 100, 0, 0, 0)
            knifeBody = Body(knifeDef, world, playerBody.position + Vec2((playerSprite.scaleX > 0) and 60 or -60, 10))
            knifeBody.group = KNIFE_GROUP
            knifeBody.velocity = Vec2(0, 0)
            world:addChild(knifeBody)
end
if currentKnifeFrame > 0 then
            knifeAnimTimer = knifeAnimTimer + deltaTime
if knifeAnimTimer >= frameDuration then
                knifeAnimTimer = 0
                currentKnifeFrame = currentKnifeFrame + 1
if currentKnifeFrame > #knifeFrames then
                    currentKnifeFrame = 0; knifeNode:removeAllChildren()
if knifeBody then knifeBody:removeFromParent(); knifeBody = nil end
else
                    knifeNode:removeAllChildren()
local s = Sprite(knifeFrames[currentKnifeFrame])
if s then
                        s.x = (playerSprite.scaleX > 0) and 60 or -30
                        s.scaleX = (playerSprite.scaleX > 0) and 1.0 or -1.0
                        s.y = 10
                        knifeNode:addChild(s)
end
end
end
end
        lastEPressed = isEDown
end)
local isButtonTriggered2 = false -- 第二个按钮是否已被刀击中
local isDoorTriggered2 = false -- 第二个门是否已被连接
local isButtonPressed2 = false -- 第二个按钮是否被手动按下（开门状态）
local buttonLight2 = nil
local swordNode2 = nil -- 注意：第二把剑要独立，不然会和第一把冲突
local swordLight2 = nil
local doorLight2 = nil
local connectionLine2 = nil -- 第二条连线
-- 创建第二条连线的函数
local function createConnectionLine2(startPos, endPos)
if connectionLine2 then connectionLine2:removeFromParent() end
    connectionLine2 = Line({startPos, endPos}, Color(255, 255, 0, 255))
    connectionLine2.zOrder = 5
    root:addChild(connectionLine2)
end
-- 实时更新第二条连线
root:schedule(function()
if connectionLine2 then
local startPos = buttonBody2:convertToWorldSpace(Vec2.zero)
local endPos
if isDoorTriggered2 then
            endPos = doorSprite2
elseif swordNode2 then
            endPos = playerBody:convertToWorldSpace(swordNode2.position + Vec2(0, swordNode2.height / 2))
end
if endPos then
            connectionLine2:set({startPos, endPos})
end
end
end)
-- 1. 刀碰到 button2
buttonBody2:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == BUTTON_TAG and not isButtonTriggered2 then
        isButtonTriggered2 = true
-- 按钮点亮
        buttonLight2 = Sprite("image/light.png")
if buttonLight2 then
            buttonLight2.scaleX = 0.5; buttonLight2.scaleY = 0.5
            buttonBody2:addChild(buttonLight2)
end
-- 玩家获得第二把剑（独立节点，防止和第一把冲突）
        swordNode2 = Sprite("image/sword.png")
if swordNode2 then
            swordNode2.x = (playerSprite.scaleX > 0) and 30 or -30
            swordNode2.y = 20
            swordNode2.scaleX = (playerSprite.scaleX > 0) and 1.0 or -1.0
            swordNode2.scaleY = 1.0
            knifeNode:addChild(swordNode2) -- 仍然挂在 knifeNode 下
end
-- 剑上的光效
        swordLight2 = Sprite("image/light.png")
if swordLight2 then
            swordLight2.scaleX = 0.5; swordLight2.scaleY = 0.5
            swordLight2.y = swordNode2.height / 2
            swordNode2:addChild(swordLight2)
end
-- 画第一段线：按钮2 → 剑
local startPos = buttonBody2:convertToWorldSpace(Vec2.zero)
local endPos = playerBody:convertToWorldSpace(swordNode2.position + Vec2(0, swordNode2.height / 2))
        createConnectionLine2(startPos, endPos)
end
end)
-- 2. 刀碰到 door2（前提是 button2 已经点亮）
doorBody2:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == DOOR_TAG and isButtonTriggered2 and not isDoorTriggered2 then
        isDoorTriggered2 = true
-- 门点亮
        doorLight2 = Sprite("image/light.png")
if doorLight2 then
            doorLight2.scaleX = 0.5; doorLight2.scaleY = 0.5
            doorBody2:addChild(doorLight2)
end
-- 剑消失（第二把剑也移除）
if swordNode2 then swordNode2:removeFromParent(); swordNode2 = nil end
if swordLight2 then swordLight2:removeFromParent(); swordLight2 = nil end
-- 画第二段线：按钮2 → 门2
local startPos = buttonBody2:convertToWorldSpace(Vec2.zero)
local endPos = doorBody2:convertToWorldSpace(Vec2.zero)
        createConnectionLine2(startPos, endPos)
end
end)
-- 3. 点击 button2 开关第二扇门
buttonSprite2:onTapped(function()
if isDoorTriggered2 then
        isButtonPressed2 = not isButtonPressed2
if isButtonPressed2 then
-- 按下状态
            buttonSprite2.textureRect = Rect(buttonW, 0, buttonW, buttonH)
            doorSprite2.textureRect = Rect(doorW, 0, doorW, doorH)
-- 把门的物理碰撞体移走（让玩家可以穿过）
            doorBody2.x = doorBody2.x + 10000
            doorSprite2.y = doorSprite2.y - 10000
else
-- 恢复状态
            buttonSprite2.textureRect = Rect(0, 0, buttonW, buttonH)
            doorSprite2.textureRect = Rect(0, 0, doorW, doorH)
-- 把门的物理体移回来
            doorBody2.x = doorBody2.x - 10000
            doorSprite2.y = doorSprite2.y + 10000
end
end
end)
-- ==========================================
-- [新增] 第三关元素：类似于第一关的石墙、按钮、木门
-- ==========================================
local wallBody3 = Body(wallDef, world, Vec2(3700, -400))
world:addChild(wallBody3)
local wallSprite3_new = Sprite("image/stone wall.png")
wallSprite3_new.scaleX = 3.0
wallSprite3_new.scaleY = 3.0
wallBody3:addChild(wallSprite3_new)

local buttonBody3 = Body(buttonDef, world, Vec2(3700, -350))
world:addChild(buttonBody3)
local buttonSprite3 = Sprite("image/wooden button.png")
if buttonSprite3 and buttonSprite3.texture then
    buttonSprite3.textureRect = Rect(0, 0, buttonW, buttonH)
end
buttonSprite3.scaleX = 2.0
buttonSprite3.scaleY = 2.0
buttonBody3:addChild(buttonSprite3)
buttonSprite3.touchEnabled = true

local doorBody3 = Body(doorDef, world, Vec2(4000, -350))
world:addChild(doorBody3)
local doorSprite3 = Sprite("image/wooden door.png")
if doorSprite3 and doorSprite3.texture then
    doorSprite3.textureRect = Rect(0, 0, doorW, doorH)
end
doorSprite3.scaleX = 2.4
doorSprite3.scaleY = 4.0
doorSprite3.y = 50
doorSprite3.x = 100
doorBody3:addChild(doorSprite3)

-- 第三关逻辑变量
local isButtonTriggered3 = false
local isDoorTriggered3 = false
local isButtonPressed3 = false
local buttonLight3 = nil
local swordNode3 = nil
local swordLight3 = nil
local doorLight3 = nil
local connectionLine3 = nil

local function createConnectionLine3(startPos, endPos)
if connectionLine3 then connectionLine3:removeFromParent() end
    connectionLine3 = Line({startPos, endPos}, Color(255, 255, 0, 255))
    connectionLine3.zOrder = 5
    root:addChild(connectionLine3)
end

root:schedule(function()
if connectionLine3 then
local startPos = buttonBody3:convertToWorldSpace(Vec2.zero)
local endPos
if isDoorTriggered3 then
            endPos = doorSprite3
elseif swordNode3 then
            endPos = playerBody:convertToWorldSpace(swordNode3.position + Vec2(0, swordNode3.height / 2))
end
if endPos then
            connectionLine3:set({startPos, endPos})
end
end
end)

buttonBody3:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == BUTTON_TAG and not isButtonTriggered3 then
        isButtonTriggered3 = true
        buttonLight3 = Sprite("image/light.png")
if buttonLight3 then
            buttonLight3.scaleX = 0.5; buttonLight3.scaleY = 0.5
            buttonBody3:addChild(buttonLight3)
end
        swordNode3 = Sprite("image/sword.png")
if swordNode3 then
            swordNode3.x = (playerSprite.scaleX > 0) and 30 or -30
            swordNode3.y = 20
            swordNode3.scaleX = (playerSprite.scaleX > 0) and 1.0 or -1.0
            swordNode3.scaleY = 1.0
            knifeNode:addChild(swordNode3)
end
        swordLight3 = Sprite("image/light.png")
if swordLight3 then
            swordLight3.scaleX = 0.5; swordLight3.scaleY = 0.5
            swordLight3.y = swordNode3.height / 2
            swordNode3:addChild(swordLight3)
end
local startPos = buttonBody3:convertToWorldSpace(Vec2.zero)
local endPos = playerBody:convertToWorldSpace(swordNode3.position + Vec2(0, swordNode3.height / 2))
        createConnectionLine3(startPos, endPos)
end
end)

doorBody3:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == DOOR_TAG and isButtonTriggered3 and not isDoorTriggered3 then
        isDoorTriggered3 = true
        doorLight3 = Sprite("image/light.png")
if doorLight3 then
            doorLight3.scaleX = 0.5; doorLight3.scaleY = 0.5
            doorBody3:addChild(doorLight3)
end
if swordNode3 then swordNode3:removeFromParent(); swordNode3 = nil end
if swordLight3 then swordLight3:removeFromParent(); swordLight3 = nil end
local startPos = buttonBody3:convertToWorldSpace(Vec2.zero)
local endPos = doorBody3:convertToWorldSpace(Vec2.zero)
        createConnectionLine3(startPos, endPos)
end
end)

buttonSprite3:onTapped(function()
if isDoorTriggered3 then
        isButtonPressed3 = not isButtonPressed3
if isButtonPressed3 then
            buttonSprite3.textureRect = Rect(buttonW, 0, buttonW, buttonH)
            doorSprite3.textureRect = Rect(doorW, 0, doorW, doorH)
            doorBody3.y = doorBody3.y + 10000
            doorSprite3.y = doorSprite3.y - 10000
else
            buttonSprite3.textureRect = Rect(0, 0, buttonW, buttonH)
            doorSprite3.textureRect = Rect(0, 0, doorW, doorH)
            doorBody3.y = doorBody3.y - 10000
            doorSprite3.y = doorSprite3.y + 10000
end
end
end)

-- ==========================================
-- [新增] 第三关后续：走过木门后右边stone wall（刚体），石墙上木门，左上方长矮石墙（刚体），上面石墙+按钮
-- ==========================================
-- 右边stone wall (wallBody4, 静态刚体)
local wallDef4 = BodyDef()
wallDef4.type = "Static"
wallDef4:attachPolygon(560, 50, 1, 0.5, 0.0) -- 长300，矮50
local wallBody4 = Body(wallDef4, world, Vec2(4500, -420))
world:addChild(wallBody4)
local wallSprite4_new = Sprite("image/stone wall.png")
wallSprite4_new.scaleX = 5.0 -- 拉长
wallSprite4_new.scaleY = 0.8 -- 矮化
wallBody4:addChild(wallSprite4_new)

-- 石墙上木门 (doorBody4)
local doorBody4 = Body(doorDef, world, Vec2(4500, -250))
world:addChild(doorBody4)
local doorSprite4 = Sprite("image/wooden door.png")
if doorSprite4 and doorSprite4.texture then
    doorSprite4.textureRect = Rect(0, 0, doorW, doorH)
end
doorSprite4.scaleX = 2.4
doorSprite4.scaleY = 4.0
doorSprite4.y = 50
doorSprite4.x = 100
doorBody4:addChild(doorSprite4)

-- 左上方长而矮的石墙 (wallBody5, 长宽设置)
local wallDef5 = BodyDef()
wallDef5.type = "Static"
wallDef5:attachPolygon(560, 50, 1, 0.5, 0.0) -- 长300，矮50
local wallBody5 = Body(wallDef5, world, Vec2(4100, -200))
world:addChild(wallBody5)
local wallSprite5_new = Sprite("image/stone wall.png")
wallSprite5_new.scaleX = 5.0 -- 拉长
wallSprite5_new.scaleY = 0.8 -- 矮化
wallBody5:addChild(wallSprite5_new)

-- 上面石墙 (wallBody6)
local wallBody6 = Body(wallDef, world, Vec2(4100, 0))
world:addChild(wallBody6)
local wallSprite6 = Sprite("image/stone wall.png")
wallSprite6.scaleX = 3.0
wallSprite6.scaleY = 3.0
wallBody6:addChild(wallSprite6)

-- 上面按钮 (buttonBody4)
local buttonBody4 = Body(buttonDef, world, Vec2(4100, 50))
world:addChild(buttonBody4)
local buttonSprite4 = Sprite("image/wooden button.png")
if buttonSprite4 and buttonSprite4.texture then
    buttonSprite4.textureRect = Rect(0, 0, buttonW, buttonH)
end
buttonSprite4.scaleX = 2.0
buttonSprite4.scaleY = 2.0
buttonBody4:addChild(buttonSprite4)
buttonSprite4.touchEnabled = true

-- 第四组逻辑变量（按钮控制门，像之前的玩法）
local isButtonTriggered4 = false
local isDoorTriggered4 = false
local isButtonPressed4 = false
local buttonLight4 = nil
local swordNode4 = nil
local swordLight4 = nil
local doorLight4 = nil
local connectionLine4 = nil

local function createConnectionLine4(startPos, endPos)
if connectionLine4 then connectionLine4:removeFromParent() end
    connectionLine4 = Line({startPos, endPos}, Color(255, 255, 0, 255))
    connectionLine4.zOrder = 5
    root:addChild(connectionLine4)
end

root:schedule(function()
if connectionLine4 then
local startPos = buttonBody4:convertToWorldSpace(Vec2.zero)
local endPos
if isDoorTriggered4 then
            endPos = doorSprite4
elseif swordNode4 then
            endPos = playerBody:convertToWorldSpace(swordNode4.position + Vec2(0, swordNode4.height / 2))
end
if endPos then
            connectionLine4:set({startPos, endPos})
end
end
end)

buttonBody4:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == BUTTON_TAG and not isButtonTriggered4 then
        isButtonTriggered4 = true
        buttonLight4 = Sprite("image/light.png")
if buttonLight4 then
            buttonLight4.scaleX = 0.5; buttonLight4.scaleY = 0.5
            buttonBody4:addChild(buttonLight4)
end
        swordNode4 = Sprite("image/sword.png")
if swordNode4 then
            swordNode4.x = (playerSprite.scaleX > 0) and 30 or -30
            swordNode4.y = 20
            swordNode4.scaleX = (playerSprite.scaleX > 0) and 1.0 or -1.0
            swordNode4.scaleY = 1.0
            knifeNode:addChild(swordNode4)
end
        swordLight4 = Sprite("image/light.png")
if swordLight4 then
            swordLight4.scaleX = 0.5; swordLight4.scaleY = 0.5
            swordLight4.y = swordNode4.height / 2
            swordNode4:addChild(swordLight4)
end
local startPos = buttonBody4:convertToWorldSpace(Vec2.zero)
local endPos = playerBody:convertToWorldSpace(swordNode4.position + Vec2(0, swordNode4.height / 2))
        createConnectionLine4(startPos, endPos)
end
end)

doorBody4:onBodyEnter(function(other, sensorTag)
if other == knifeBody and sensorTag == DOOR_TAG and isButtonTriggered4 and not isDoorTriggered4 then
        isDoorTriggered4 = true
        doorLight4 = Sprite("image/light.png")
if doorLight4 then
            doorLight4.scaleX = 0.5; doorLight4.scaleY = 0.5
            doorBody4:addChild(doorLight4)
end
if swordNode4 then swordNode4:removeFromParent(); swordNode4 = nil end
if swordLight4 then swordLight4:removeFromParent(); swordLight4 = nil end
local startPos = buttonBody4:convertToWorldSpace(Vec2.zero)
local endPos = doorBody4:convertToWorldSpace(Vec2.zero)
        createConnectionLine4(startPos, endPos)
end
end)

buttonSprite4:onTapped(function()
if isDoorTriggered4 then
        isButtonPressed4 = not isButtonPressed4
if isButtonPressed4 then
            buttonSprite4.textureRect = Rect(buttonW, 0, buttonW, buttonH)
            doorSprite4.textureRect = Rect(doorW, 0, doorW, doorH)
            doorBody4.y = doorBody4.y + 10000
            doorSprite4.y = doorSprite4.y - 10000
else
            buttonSprite4.textureRect = Rect(0, 0, buttonW, buttonH)
            doorSprite4.textureRect = Rect(0, 0, doorW, doorH)
            doorBody4.y = doorBody4.y - 10000
            doorSprite4.y = doorSprite4.y + 10000
end
end
end)

end
-- ====== [修改后] 星空桥梁场景 (Bridge Scene) ======
createBridgeScene = function()
    root:removeAllChildren()
    currentState = GameState.BRIDGE
-- 1. [修改] 使用自适应背景
    createAdaptBackground(root, "image/starry sky.jpg", Color(10, 10, 40, 255))
-- 2. 物理世界
local world = PhysicsWorld()
    world.gravity = Vec2(0, -3000)
    world.showDebug = true -- 调试用
    root:addChild(world)
    world:setShouldContact(0, 0, true)
-- 3. [修改] 拱形桥 (地面)
local bridgeDef = BodyDef()
    bridgeDef.type = "Static"
-- 生成拱形顶点数据
local vertices = {}
local bridgeWidth = 1400
local archHeight = 180 -- 拱起的高度
local segments = 30 -- 分段数，越大约圆滑
for i = 0, segments do
-- x 从 -halfWidth 到 +halfWidth
local t = i / segments
local x = -bridgeWidth / 2 + (bridgeWidth * t)
-- 使用抛物线公式生成拱形: y = H * (1 - (x / (W/2))^2)
local normalizedX = x / (bridgeWidth / 2)
local y = archHeight * (1 - normalizedX * normalizedX)
        table.insert(vertices, Vec2(x, y))
end
-- 使用 Chain 形状来模拟地面表面
    bridgeDef:attachChain(vertices, 0.8, 0.0)
-- 将桥的刚体位置稍微放低一点，因为拱形是向上的
local bridgeBody = Body(bridgeDef, world, Vec2(0, -350))
    world:addChild(bridgeBody)
local bridgeSprite = Sprite("image/bridge.png")
if bridgeSprite then
        bridgeSprite.scaleX = 10.0
        bridgeSprite.scaleY = 4.0
-- 图片位置微调，使其贴合拱形物理框
        bridgeSprite.position = Vec2(0, 120)
        bridgeBody:addChild(bridgeSprite)
else
-- 兜底显示
local debugBridge = Sprite()
        debugBridge.size = Vec2(1200, 20)
        debugBridge.color = Color(150, 150, 150, 255)
        bridgeBody:addChild(debugBridge)
end
-- 4. 主角
local playerDef = BodyDef()
    playerDef.type = "Dynamic"
    playerDef.linearDamping = 0.0
    playerDef.fixedRotation = true
    playerDef:attachPolygon(50, 50, 1, 0.0, 0.0)
-- 主角初始位置
local playerBody = Body(playerDef, world, Vec2(-500, 0))
    world:addChild(playerBody)
-- [修改] 使用精灵表 (walk.png) 替代 character.png
local playerSprite = Sprite("image/walk.png")
local frameWidth = 0
local frameHeight = 0
if playerSprite and playerSprite.texture then
-- 计算单帧大小 (4帧)
        frameWidth = playerSprite.texture.width / 4
        frameHeight = playerSprite.texture.height
-- 初始显示第 2 帧 (Stand)
        playerSprite.textureRect = Rect(frameWidth, 0, frameWidth, frameHeight)
else
        playerSprite = Sprite("default.png")
end
-- 缩放比例设为 0.4
    playerSprite.scaleX = 0.6
    playerSprite.scaleY = 2.0
    playerBody:addChild(playerSprite)
        playerSprite.y=80
-- ==========================================
-- 5. 剑 (Sensor)
-- ==========================================
local swordDef = BodyDef()
    swordDef.type = "Static"
local SWORD_TAG = 1
    swordDef:attachDiskSensor(SWORD_TAG, Vec2(0, 0), 70)
-- 把剑放在拱桥中间偏上的位置
local swordBody = Body(swordDef, world, Vec2(0, -130))
    world:addChild(swordBody)
local swordSprite = Sprite("image/sword.png")
if swordSprite then
        swordSprite.scaleX = 4.0; swordSprite.scaleY = 4.0;
        swordBody:addChild(swordSprite)
                swordSprite.y=-100
else
local debugSword = Sprite()
        debugSword.size = Vec2(20, 60)
        debugSword.color = Color(255, 255, 0, 255)
        swordBody:addChild(debugSword)
end
-- ==========================================
-- 6. 传送门 (Sensor)
-- ==========================================
local portalDef = BodyDef()
    portalDef.type = "Static"
local PORTAL_TAG = 2
    portalDef:attachDiskSensor(PORTAL_TAG, Vec2(0, 0), 60)
-- 放在桥右侧
local portalBody = Body(portalDef, world, Vec2(500, -200))
    world:addChild(portalBody)
local portalSprite = Sprite("image/portal.png")
if portalSprite then
        portalSprite.scaleX = 3.0; portalSprite.scaleY = 3.0;
        portalBody:addChild(portalSprite)
                portalSprite.y=50
else
local debugPortal = Sprite()
        debugPortal.size = Vec2(80, 120)
        debugPortal.color = Color(0, 255, 255, 255)
        portalBody:addChild(debugPortal)
end
-- ==========================================
-- 7. 逻辑控制与对话框
-- ==========================================
local isSwordTriggered = false
local canMove = true
local contactCount = 0
    playerBody:onContactStart(function(other)
if other == bridgeBody then contactCount = contactCount + 1 end
end)
    playerBody:onContactEnd(function(other)
if other == bridgeBody then contactCount = contactCount - 1 end
end)
local function showItemDialog(text, callback)
        canMove = false
        playerBody.velocity = Vec2(0, 0)
local dialogLayer = Node()
        dialogLayer.size = App.visualSize
        dialogLayer.touchEnabled = true
        root:addChild(dialogLayer)
local box = Sprite("image/dialog box.png")
if not box then
            box = Sprite()
            box.size = Vec2(600, 150)
            box.color = Color(0, 0, 0, 200)
end
-- [修改] 对话框居中 (y=0)
        box.x = 700
        box.y = 120
        dialogLayer:addChild(box)
local label = Label("Sarasa-Mono-SC-Regular", 30)
        label.text = text
        label.color = Color(255, 255, 255, 255)
        box:addChild(label)
        dialogLayer:onTapEnded(function()
            dialogLayer:removeFromParent()
            canMove = true
if callback then callback() end
end)
end
-- ==========================================
-- 8. 碰撞事件处理
-- ==========================================
    swordBody:onBodyEnter(function(other, sensorTag)
if other == playerBody and sensorTag == SWORD_TAG and not isSwordTriggered then
            isSwordTriggered = true
            showItemDialog("这是什么东西，明明没有桥络，却有这么强的光\n(点击继续)", function()
                swordBody:removeFromParent()
end)
end
end)
    portalBody:onBodyEnter(function(other, sensorTag)
if other == playerBody and sensorTag == PORTAL_TAG then
            canMove = false
            playerBody.velocity = Vec2(0, 0)
local blackScreen = Sprite()
            blackScreen.size = App.visualSize
            blackScreen.color = Color(0, 0, 0, 0)
            blackScreen.zOrder = 100
            root:addChild(blackScreen)
            threadLoop(function()
local t = 0
while t < 1.0 do
                    t = t + App.deltaTime
                    blackScreen.color = Color(0, 0, 0, math.floor(math.min(t, 1) * 255))
                    coroutine.yield()
end
                createSkyGrassScene() -- 修改为跳转到新场景
return true
end)
end
end)
-- ==========================================
-- 9. 玩家移动
-- ==========================================
local lastSpacePressed = false
-- [新增] 动画变量
local animTimer = 0
local animInterval = 0.12
local frameIndex = 1
    playerBody:schedule(function(deltaTime)
if not canMove then return end
local currentVel = playerBody.velocity
local moveSpeed = 300
local jumpForce = 1200
local targetVx = 0
local targetVy = currentVel.y
local isMoving = false
if Keyboard:isKeyPressed("A") then
            targetVx = -moveSpeed
if playerSprite.scaleX > 0 then playerSprite.scaleX = -math.abs(playerSprite.scaleX) end
            isMoving = true
elseif Keyboard:isKeyPressed("D") then
            targetVx = moveSpeed
if playerSprite.scaleX < 0 then playerSprite.scaleX = math.abs(playerSprite.scaleX) end
            isMoving = true
end
-- [新增] 动画更新逻辑
if isMoving and playerSprite.texture then
            animTimer = animTimer + deltaTime
if animTimer >= animInterval then
                animTimer = 0
                frameIndex = (frameIndex + 1) % 4
                playerSprite.textureRect = Rect(frameIndex * frameWidth, 0, frameWidth, frameHeight)
end
elseif playerSprite.texture then
-- 停止移动时恢复站立帧 (Index 1)
if frameIndex ~= 1 then
                frameIndex = 1
                playerSprite.textureRect = Rect(frameIndex * frameWidth, 0, frameWidth, frameHeight)
end
end
local isSpaceDown = Keyboard:isKeyPressed("Space")
local isSpaceJustPressed = isSpaceDown and not lastSpacePressed
local isGrounded = (contactCount > 0) and (math.abs(currentVel.y) < 5.0)
if isSpaceJustPressed and isGrounded then
            targetVy = jumpForce
end
        targetVy = targetVy + (world.gravity.y * deltaTime)
if targetVy > 0 and not isSpaceDown then targetVy = targetVy + (world.gravity.y * 2.0 * deltaTime) end
if targetVy < 0 then targetVy = targetVy + (world.gravity.y * 0.5 * deltaTime) end
        playerBody.velocity = Vec2(targetVx, targetVy)
if playerBody.y < -800 then
            playerBody.position = Vec2(-400, 0)
            playerBody.velocity = Vec2(0, 0)
end
        lastSpacePressed = isSpaceDown
end)
end
-- ====== 医院序章场景 (Hospital Scene) ======
createHospitalScene = function()
    root:removeAllChildren()
        Audio:stopStream()
        Audio:playStream("music/hospital2.MP3")
--backhos.volume=0.7
--currentState = GameState.PROLOGUE
    currentState = GameState.HOSPITAL
-- [修改] 使用自适应背景
    createAdaptBackground(root, "image/hospital.jpg", Color(200, 200, 200, 255))
-- [新增] 窗户图片
local window = Sprite("image/window.png")
if not window then
        window = Sprite()
        window.size = Vec2(150, 150)
        window.color = Color(150, 200, 255, 255) -- 蓝色调作为窗户的兜底色
end
    window.position = Vec2(-200, 0) -- 放置在右上方
    window.scaleX = 0.4; window.scaleY = 0.4;
    root:addChild(window)
local bed = Sprite("image/bed.png")
if not bed then bed = Sprite(); bed.size = Vec2(200, 100); bed.color = Color(255, 255, 255, 255) end
    bed.position = Vec2(-500, -400); bed.scaleX = 0.45; bed.scaleY = 0.2; root:addChild(bed)
local char = Sprite("image/sleep.png")
if not char then char = Sprite("default.png") end
    char.position = bed.position + Vec2(-60, 80); char.scaleX = 2.5; char.scaleY = 2.0; char.angle = 0; root:addChild(char)
local door = Sprite("image/enddoor.png")
local doorW, doorH = 100, 200
if door then doorW = door.width; doorH = door.height end
local doorRectClosed = Rect(0, 0, doorW / 2, doorH); local doorRectOpen = Rect(doorW / 2, 0, doorW / 2, doorH)
if not door then door = Sprite() end
    door.textureRect = doorRectClosed; door.scaleX = 2.0; door.scaleY = 6.0; door.position = Vec2(600, -50); root:addChild(door)
local tipLabel = Label("Sarasa-Mono-SC-Regular", 24)
    tipLabel.text = ""; tipLabel.color = Color(255, 255, 255, 255); tipLabel.position = Vec2(300, -50); root:addChild(tipLabel)
local canMove = false
local texts = { "医生：患者生命体征还在持续下降，全身检查做了三遍，没找到任何器质性病变，我们已经尽力了，无力回天。",
"主角：我这是……死了吗？",
"只有死人，才没有“桥络”。",
"死了也好，像我这样的人活着，只会添更多麻烦，造更多孽。",
"只是……死了之后，该往哪去？"}
local textIndex = 1; local isDialogFinished = false
local dialogLayer = Node(); dialogLayer.size = App.visualSize; dialogLayer.touchEnabled = true; root:addChild(dialogLayer)
local dialogBox, contentLabel
    dialogLayer:onTapEnded(function()
if not isDialogFinished then
if not dialogBox then
                dialogBox = Sprite("image/dialog box.png") or Sprite()
                dialogBox.scaleX = 10.0
                dialogBox.scaleY = 2.0
if not dialogBox.texture then dialogBox.size = Vec2(600, 150); dialogBox.color = Color(0, 0, 0, 200) end
                dialogBox.y = -400; root:addChild(dialogBox)
                contentLabel = Label("Sarasa-Mono-SC-Regular", 30); contentLabel.color = Color(255, 255, 255, 255); contentLabel.position = Vec2(0, -420); root:addChild(contentLabel)
end
if textIndex <= #texts then contentLabel.text = texts[textIndex] end
            textIndex = textIndex + 1
if textIndex > #texts + 1 then
                isDialogFinished = true; dialogLayer.touchEnabled = false; dialogBox:removeFromParent(); contentLabel:removeFromParent()
if char then char:removeFromParent() end
-- [新增] 替换为 Sprite Sheet 动画 (walk.png)
-- 假设 walk.png 有 4 帧（Step, Stand, Step, Stand）
                char = Sprite("image/walk.png")
local frameWidth = 0
local frameHeight = 0
if char and char.texture then
-- 计算单帧大小
                    frameWidth = char.texture.width / 4
                    frameHeight = char.texture.height
-- 初始显示第 2 帧 (Stand)
                    char.textureRect = Rect(frameWidth, 0, frameWidth, frameHeight)
else
                    char = Sprite("default.png")
end
                char.position = bed.position + Vec2(150, 50)
                char.scaleX = 0.6
                char.scaleY = 2.0
                root:addChild(char)
                canMove = true
-- 保存尺寸给 update 使用
                char.frameWidth = frameWidth
                char.frameHeight = frameHeight
end
end
end)
-- 动画计时器
local animTimer = 0
local animInterval = 0.12 -- 动画速度
local frameIndex = 1 -- 当前帧索引 (0-3)
    root:schedule(function(deltaTime)
if currentState ~= GameState.HOSPITAL then return true end
if not canMove or not char then return end
local moveSpeed = 300
local isMoving = false
if Keyboard:isKeyPressed("A") then
            char.x = char.x - moveSpeed * deltaTime
if char.scaleX > 0 then char.scaleX = -math.abs(char.scaleX) end
if char.x < -400 then char.x = -400 end
            isMoving = true
elseif Keyboard:isKeyPressed("D") then
            char.x = char.x + moveSpeed * deltaTime
if char.scaleX < 0 then char.scaleX = math.abs(char.scaleX) end
if char.x > 550 then char.x = 550 end
            isMoving = true
end
-- [新增] 动画播放逻辑
if isMoving and char.texture then
            animTimer = animTimer + deltaTime
if animTimer >= animInterval then
                animTimer = 0
                frameIndex = (frameIndex + 1) % 4 -- 0, 1, 2, 3 循环
local rect = Rect(frameIndex * char.frameWidth, 0, char.frameWidth, char.frameHeight)
                char.textureRect = rect
end
elseif char.texture then
-- 停止时重置为站立帧 (索引 1)
if frameIndex ~= 1 then
                frameIndex = 1
local rect = Rect(frameIndex * char.frameWidth, 0, char.frameWidth, char.frameHeight)
                char.textureRect = rect
end
end
if math.abs(char.x - door.x) < 80 then
            tipLabel.text = "按E开门"
                        tipLabel.color = Color(0, 0, 0, 255)
                        tipLabel.x=400
                        tipLabel.scaleX=2.0
                        tipLabel.scaleY=2.0
if Keyboard:isKeyPressed("E") then
                canMove = false; if door then door.textureRect = doorRectOpen end
local blackScreen = Sprite(); blackScreen.size = App.visualSize; blackScreen.color = Color(0, 0, 0, 0); blackScreen.zOrder = 100; root:addChild(blackScreen)
                threadLoop(function()
local t = 0; while t < 1.0 do t = t + App.deltaTime; blackScreen.color = Color(0, 0, 0, math.floor(math.min(t, 1) * 255)); coroutine.yield() end
                    createBridgeScene() -- 跳转到桥梁
return true
end)
end
else tipLabel.text = "" end
end)
end
-- ====== 序章场景 (Underwater) ======
createPrologueScene = function()
    root:removeAllChildren()
        Audio:stopStream()
--Audio:stop(inc)
        Audio:playStream("music/underwater.mp3")
    currentState = GameState.PROLOGUE
-- [修改] 使用自适应背景
    createAdaptBackground(root, "image/underwater.jpg", Color(0, 0, 100, 255))
local texts = { "大人们总说，人死了会被鬼差勾走魂魄，见着熬汤的孟婆，踏过奈何桥，洗去尘世所有记忆，才算真正去往死者的世界。",
"我从没信过这些——多半是世人见多了小人得利、善恶失衡，盼着那些坏人能有报应，才编出来的慰藉罢了",
"说到底，我会这么想，不过是因为我也算个坏人，怕真有报应，怕被惩罚。",
"我打小就有个怪能力，能看见万物间缠绕的无形丝线，第一次瞧见时，心里就莫名冒出两个字：“桥络”",
"父母靠着我的能力帮人算命，慕名来的人挤破了门。",
"有人借这能力寻姻缘，有人想断了和某个人的牵扯，还有人来查伴侣是不是出了轨。",
"可我其实什么都做不了。我只能看见“桥络”存在，既改不了它的强弱，也看不清丝线那头藏着的具体纠葛。",
" 盼姻缘的，循着丝线找去，遇上的却是宿敌；",
"想断联的，两人间的“桥络”反倒缠得更紧；疑心妻子出轨的，见着一丝联系就笃定罪名，闹得家破人亡。",
"我是个坏人，窥见了改变不了的因果，却眼睁睁看着悲剧发生。",
"我无能，所以我有罪。",
"若我从没见过这“桥络”，若我从没来到这世上，或许就不会有这么多遗憾了。"}
local idx = 1
local layer = Node(); layer.size = App.visualSize; layer.touchEnabled = true; root:addChild(layer)
local box, lbl
local talk
    layer:onTapEnded(function()
if talk then Audio:stop(talk) end
                talk = Audio:play("music/speach.MP3")
if not box then
            box = Sprite("image/dialog box.png") or Sprite()
            box.scaleX = 10.0
            box.ScaleY = 6.0
if not box.texture then box.size = {600, 150}; box.color = Color(0, 0, 0, 200) end
            box.y = -150; root:addChild(box)
            lbl = Label("Sarasa-Mono-SC-Regular", 30); lbl.color = Color(255, 255, 255, 255); lbl.position = Vec2(0, -170); root:addChild(lbl)
end
if idx <= #texts then lbl.text = texts[idx] end
        idx = idx + 1
if idx > #texts + 1 then
if talk then Audio:stop(talk) end
            layer.touchEnabled = false; createHospitalScene()
end
end)
end
-- ====== 菜单场景 ======
createMenuScene = function()
if pauseLayer then pauseLayer:removeFromParent() pauseLayer = nil end
    Audio:playStream("music/insect.mp3")
        Audio:playStream("music/星夜.MP3")
-- [修改] 使用自适应背景
    createAdaptBackground(root, "image/background.jpg", Color(50, 50, 50, 255))
local btn = Sprite("image/start button.png") or Sprite()
if not btn.texture then btn.size = {100, 100}; btn.color = Color(0, 255, 0, 255) end
    btn.y = -50; btn.scale = 1.5
    btn:onTapBegan(function() btn.file = "image/start button2.png" end)
    btn:onTapEnded(function() btn.file = "image/start button.png" end)
    btn:onTapped(function() createPrologueScene() end)
    root:addChild(btn)
local title = Sprite("image/title.png"); if title then title.y = 350; title.scaleX = 4; title.scaleY = 4; root:addChild(title) end
local quit = Sprite("image/back button.png"); if quit then quit.y = -200; quit.scale = 0.6; quit:onTapBegan(function() App:shutdown() end); root:addChild(quit) end
end
local function initGame()
if currentState == GameState.MENU then createMenuScene() else createGameScene() end
end
threadLoop(function()
while true do
if currentState == GameState.GAMEPLAY and isImGuiMenuOpen then
            ImGui.SetNextWindowPos(Vec2(App.visualSize.width - 20, 20), "Always", Vec2(1, 0))
            ImGui.Begin("GameMenu", {"NoDecoration", "AlwaysAutoResize", "NoMove", "NoSavedSettings"}, function()
                ImGui.Text("游戏菜单"); ImGui.Separator()
if ImGui.Button("返回主界面", Vec2(120, 30)) then
                    Audio:stopStream(0.5); root:removeAllChildren()
                    currentState = GameState.MENU; isImGuiMenuOpen = false
                    createMenuScene()
end
if ImGui.Button("退出游戏", Vec2(120, 30)) then App:shutdown() end
end)
end
        coroutine.yield()
end
end)
root:onKeyDown(function(k) if currentState == GameState.GAMEPLAY and k == "Escape" then isImGuiMenuOpen = not isImGuiMenuOpen end end)
initGame()
return root